package istar.impl;

import istar.IActor;
import istar.IDependency;
import istar.IElement;
import istar.IRole;
import istar.ITask;
import istar.agent.IstarJadeAgent;
import jade.content.AgentAction;

import java.util.Iterator;
import java.util.List;
import java.util.Vector;



public class Task extends AbstractElement implements ITask, AgentAction {

	private boolean processed = false;
	private double cost;
	private Object[] params;
	private TaskDecompositionLink myDecompositionLink; 
	private List<MeansEndLink> meansFor = new Vector<MeansEndLink>();
	private List<ContributionLink> contributionsFor = new Vector<ContributionLink>();
	
	@Override
	public Object clone(IActor newOwner) throws CloneNotSupportedException {
		Task newClone = (Task)super.clone(newOwner);
		newClone.meansFor = new Vector<MeansEndLink>();
		newClone.cost = this.cost;
		if (myDecompositionLink!=null){
			TaskDecompositionLink taskDecClone = (TaskDecompositionLink)myDecompositionLink.clone(newOwner);
			try {
				taskDecClone.setOwner(newClone);
			} catch (Exception e) {
				e.printStackTrace();
			}

			newClone.myDecompositionLink = taskDecClone;
		}
		newClone.params = this.params;
		newClone.processed = this.processed;
		
		if (this.myDecompositionLink!=null){
			if (this.myDecompositionLink.getTargetElements().size()!=newClone.getMyDecompositionLink().getTargetElements().size())
				System.out.println("Erro grave! original means-ends diferente do clone");
			
		}
		
		
		return newClone;
	}
	
	public Task(String _name){
		super(_name);
	}
	
	public Task(String _name, IActor actor){
		super(_name, actor);
	}
	
	public Task(String _name, IActor actor, Object[]  _params){
		super(_name, actor);
		this.params = _params;
	}
	
	public Task(String _name, double _cost){
		super(_name);
		this.cost = _cost;
	}
	
	@Override
	public List<ContributionLink> getContributesFor() {
		return this.contributionsFor;
	}
	
	/*
	@Override
	public List<TaskDecompositionLink> getMyDecompositionLinks() {
		return myDecompositionLinks;
	}

	@Override
	public void setMyDecompositionLink(List<TaskDecompositionLink> _decompositionLinks){
		this.myDecompositionLinks = _decompositionLinks;
	}
	*/
	

	@Override
	public List<MeansEndLink> getMeansFor() {
		return this.meansFor;
	}

	@Override
	public Object[] getParams() {
		return params;
	}

	@Override
	public void setParams(Object[]  params) {
		this.params = params;
	}

	@Override
	public double getCost() {
		return this.cost;
	}

	@Override
	public void setCost(double _cost) {
		this.cost = _cost;
	}

	@Override
	public boolean getProcessed() {
		return this.processed;
	}

	@Override
	public void setProcessed(boolean value) {
		this.processed = value;
		if (value==true){
			Iterator<MeansEndLink> itEnds = this.meansFor.iterator();
			while (itEnds.hasNext()){
				IElement end = itEnds.next().getOwner();
				if (end.getClass().equals(Goal.class)){
					((Goal)end).setState(IElement.SATISFIED);
					continue;
				}
				
				try {
					AbstractMainGoal main = (AbstractMainGoal)end;
					main.setState(IElement.SATISFIED);
					continue;
				} catch (ClassCastException ce) {
					// TODO: handle exception
				} catch (Exception e) {
					System.out.println(e.getMessage());
				}
				
				((AbstractElement)end).setAchieved(true);
			}
		}
	}

	
	
	public TaskDecompositionLink getMyDecompositionLink() {
		return myDecompositionLink;
	}

	public void setMyDecompositionLink(TaskDecompositionLink myDecompositionLink) {
		this.myDecompositionLink = myDecompositionLink;
	}

	@Override
	public boolean workable(IActor actor) {
		if (able(actor)){
			if (this.isBasic()){
				return true;
			}
			else{
				if (this.myDecompositionLink==null){
					return false;
				}
				else {
					Iterator<IElement> itSubElmnts = this.myDecompositionLink.getTargetElements().iterator();
					while (itSubElmnts.hasNext()){
						IElement subElmnt = itSubElmnts.next();
						if (subElmnt.getOwner()!=actor){
							Iterator<IDependency> itDeps = subElmnt.getDependencies().iterator();
							while (itDeps.hasNext()){
								Dependency dep = (Dependency)itDeps.next();
								if (dep.getDependerElement()==this){
									if (!dep.getDependeeElement().workable((IActor)dep.getDependee()))
										return false;
								}
							}
						} 
						else{
							if (!subElmnt.workable(actor))
								return false;
						}
					}
					return true;	
				}
			}
		}
		else 
			return false;
	}
	
	@Override
	public boolean viable(IActor actor) {
		
		if (workable(actor)){
			Iterator<MeansEndLink> itLinks = meansFor.iterator();
			while (itLinks.hasNext()){
				MeansEndLink link = itLinks.next();
				if (link.getClass().equals(ContributionLink.class)){
					if (((ContributionLink)link).getValue()==ContributionLink.BREAK)
						return false;
					if (((ContributionLink)link).getValue()==ContributionLink.HURT){
						Softgoal softgoal = (Softgoal)link.getOwner();
						if (softgoal.getState()< UNDECIDED)
							return false;
					}
				}
			}
			
			if (actor.getClass()==IstarJadeAgent.class){
				Iterator<IRole> itRoles = ((IstarJadeAgent)actor).getPlays().iterator();
				while (itRoles.hasNext()){
					IRole role = itRoles.next();
					if (!this.viable(role)){
						return false;
					}
				}
				
			}
		}
		else {
			return false;
		}

		return true;
	}

	@Override
	public boolean believiable(IstarJadeAgent agent) {
		/*if (workable(agent)){
			Iterator<Belief> itBelieves = agent.getBeliefs().iterator();
			while (itBelieves.hasNext()){
				Belief belief = itBelieves.next();
				if (belief.getTopic().equals(this)){
					if ((this.assess(belief)==Belief.POSITIVE) ||
						(this.assess(belief)==Belief.STRONGLY_POSITIVE))
						return true;
					else
						return false;
				}
			}
		}
		return false;
		*/
		if (this.believiability(agent)>0)
			return true;
		else 
			return false;
	}
	
	@Override
	public double believiability(IstarJadeAgent agent) {
		double believiability = 0;
		//if (workable(agent)){
			Iterator<Belief> itBelieves = agent.getBeliefs().iterator();
			while (itBelieves.hasNext()){
				Belief belief = itBelieves.next();
				believiability += belief.getAssessment(this);
			}
		//}
		return believiability;
	}

	/*
	private Double assess(Belief _belief){
		return _belief.getAssessment(this);
	}
	*/
	@Override
	public boolean perform(IstarJadeAgent agent) {
		if (this.isBasic()){
			
			
		}
		else {
			
	
		}
		
		return false;
	}

	@Override
	public int getContributionScore() {
		int score=0;
		Iterator<MeansEndLink> itMeansEndLinks = this.getMeansFor().iterator();
		while (itMeansEndLinks.hasNext()){
			MeansEndLink meansEndLink = itMeansEndLinks.next();
			if (meansEndLink.getClass()==ContributionLink.class){
				score += ((ContributionLink)meansEndLink).getValue();
			}
		}
		return score;
	}

	@Override
	public boolean achieved() {
		// TODO Auto-generated method stub
		return (this.processed);
	}

	/*
	@Override
	public void setSubOwner() {
		// TODO Auto-generated method stub
		super.setSubOwner();
		if (this.myDecompositionLink!=null){
			Iterator<IElement> itSubs = this.myDecompositionLink.getTargetElements().iterator();
			while (itSubs.hasNext()){
				IElement subElmnt = itSubs.next();
				if (subElmnt.getOwner()!=null){
					subElmnt.setOwner(this.getOwner());
					((AbstractElement)subElmnt).setSubOwner();
				}
			}
		}
		
	}
	*/

	@Override
	public void setExecutionNumber(String executionNumber) {
		super.setExecutionNumber(executionNumber);

		if (myDecompositionLink!=null){
			Iterator<IElement> itSubs = this.myDecompositionLink.getTargetElements().iterator();
			while (itSubs.hasNext()){
				AbstractElement subElmnt = (AbstractElement)itSubs.next();
				subElmnt.setExecutionNumber(executionNumber);
			}
		}
	}

	@Override
	public void clear() {
		// TODO Auto-generated method stub
		super.clear();
		
		if (this.myDecompositionLink!=null){
			for(int i=0;i<this.myDecompositionLink.getTargetElements().size();i++){
				IElement subTask = this.myDecompositionLink.getTargetElements().get(i);
				subTask.clear();
			}
		}
		
	}
		
	
	
	
}
